<?php

/**
 * 
 * @author phuongtn1@fpt.net
 */
class Fpt_Business_Block_Adapter_Redis
{
        /**
     * @var system_model Singleton instance
     */
    protected static $_instance;
    /**
     * String detail of 1 layout 
     */
    const LayoutDetail = "layout_detail";
    /**
     * Array blockID of 1 block list 
     */
    const BlockList = "block_list";
    
    const LayoutID = "layout_id";
    
    const BlockID = "block_id";
    
    const SectionID = "section_id";
    
    const SectionDetail = "section_detail";
    
    const SectionList   = "section_blocks_list";

    const BlockDetail   = "block_detail";
    
    const MapLayout     = "map_layout";
    
    const MapSectionBlock  = "map_section_block";


    /**
     * Avoid directly create instance
     */
    private function __construct()
    {

    }

    /**
     * Retrieve singleton instance
     *
     * @return system_model
     */
    public static function getInstance()
    {
        if (null === self::$_instance)
        {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    /**
     * Reset the singleton instance
     *
     * @return void
     */
    public static function resetInstance()
    {
        self::$_instance = null;
    }

    /**
     * Return key for type & arg in layout only
     * @param string $type
     * @param string $args
     * @return string
     * @throws Core_Exception 
     */
    public function getKeyByType($type, $args)
    {
        try
        {
            $keyCaching = '';
            switch ($type)
            {
                case self::LayoutDetail:
                    $keyCaching = Fpt_Caching_Redis::makeRedisKey(self::LayoutDetail, $args);
                    break;
                case self::BlockList:
                    $keyCaching = Fpt_Caching_Redis::makeRedisKey(self::BlockList, $args);
                    break; 
                case self::LayoutID:
                    $keyCaching = Fpt_Caching_Redis::makeRedisKey(self::LayoutID, $args);
                    break; 
                case self::BlockID:
                    $keyCaching = Fpt_Caching_Redis::makeRedisKey(self::BlockID, $args);
                    break; 
                case self::BlockDetail:
                    $keyCaching = Fpt_Caching_Redis::makeRedisKey(self::BlockDetail, $args);
                    break;
                case self::SectionID:
                    $keyCaching = Fpt_Caching_Redis::makeRedisKey(self::SectionID, $args);
                    break;
                case self::SectionDetail:
                    $keyCaching = Fpt_Caching_Redis::makeRedisKey(self::SectionDetail, $args);
                    break;
                case self::SectionList:
                    $keyCaching = Fpt_Caching_Redis::makeRedisKey(self::SectionList, $args);
                    break;
                case self::MapLayout:
                    $keyCaching = Fpt_Caching_Redis::makeRedisKey(self::MapLayout, $args);
                    break;
                case self::MapLayoutDetail:
                    $keyCaching = Fpt_Caching_Redis::makeRedisKey(self::MapLayoutDetail, $args);
                    break;
                case self::MapSectionBlock:
                    $keyCaching = Fpt_Caching_Redis::makeRedisKey(self::MapSectionBlock, $args);
                    break;
               
                default :
                    throw new Core_Exception('wrong key', -1);
                    break;
            }
            return $keyCaching;
        }
        catch(Exception $ex)
        {
             throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }



    /**
     * Add layout
     * @param array $params
     * @return type
     * @throws Core_Exception 
     */
    public function addLayout($params)
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
            //make redis key
            $keyLayout = Fpt_Caching_Redis::makeRedisKey(self::LayoutDetail, $params['layoutName']);
            //encode params
            $params = Zend_Json::encode($params);
            $oldParams = $redisInstance->get($keyLayout);
            
            
            if($oldParams!= false)
            {
                //decode old block
                $oldParams = Zend_Json::decode($oldParams);
                $params = Zend_Json::decode($params);
                
                $oldParams['section'] = is_array($oldParams['section'])?$oldParams['section']:array();
                
                array_push($oldParams['section'], $params['section'][0]);
                $oldParams['section'] = array_unique($oldParams['section']);
                $params['section'] = $oldParams['section'];
               
                $params = Zend_Json::encode($params);
            }
           
            //set value to cache
            $return = $redisInstance->set($keyLayout, $params);
            
            return $return;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    /**
     * Map 1 layout with params: CateID & Controller
     * @param array $params array(CateID, Controller)
     * @return bool
     * @throws Core_Exception 
     */
    public function mapLayout($params)
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
            //make redis key
            $arrKeys = array($params['CateID'], $params['Module'], $params['Controller'], $params['Action']);
            $keyLayout = Fpt_Caching_Redis::makeRedisKey(self::MapLayout, $arrKeys);
            //encode params
            $params = Zend_Json::encode($params);
            
            //detail
            
            //set detail to cache
            $return = $redisInstance->set($keyLayout, $params);
            
            return $return;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    
    
    public function mapBlockSection($params, $isUpdate)
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);

            //make redis key
            $arrKeys = array($params['BlockName'], $params['BlockSection']);
            
            $keyMapSectionBlock = Fpt_Caching_Redis::makeRedisKey(self::MapSectionBlock, $arrKeys);
            
            //encode params
            $params['BlockParams'] = Zend_Json::encode($params['BlockParams']);
            
//            $rsMap =  $redisInstance->set($keyMapDetail, $params['BlockParams']);
            
            $keySectionList = Fpt_Caching_Redis::makeRedisKey(self::SectionList, $params['BlockSection']);

            $length = $redisInstance->hLen($keySectionList);
//            $length++;
            //set detail to cache
            $return = $redisInstance->hSet($keyMapSectionBlock, $length, $params['BlockParams']);
           
            return $return;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    
    /**
     * remove 1 map from 1 section_block_maps by order
     * @param string $sectionName
     * @param string $blockName
     * @param int $order block order in this map
     * @return bool
     * @throws Core_Exception 
     */
    public function removeMapBlockSection($sectionName, $blockName, $order=0)
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
   
            //make redis key
            $arrKeys = array($blockName, $sectionName);
            //generate key
            $keyMapSectionBlock = Fpt_Caching_Redis::makeRedisKey(self::MapSectionBlock, $arrKeys);
            //delete map
            $keySectionList = Fpt_Caching_Redis::makeRedisKey(self::SectionList, $sectionName);
            
            $rs = $redisInstance->hDel($keySectionList, $order); 
            
            $blockName = $redisInstance->hGetAll($keyMapSectionBlock);//, $order);
            
            $return = $redisInstance->hDel($keyMapSectionBlock, $order);
            
            
            return $return;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }

    /**
     * edit map block section
     * @param type $sectionName
     * @param type $blockName
     * @param type $order
     * @param type $blockParams
     * @return type
     * @throws Core_Exception 
     */
    public function editMapBlockSection($sectionName, $blockName, $order = 0, $blockParams = array())
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
   
            //make redis key
            $arrKeys = array($blockName, $sectionName);
            //generate key
            $keyMapSectionBlock = Fpt_Caching_Redis::makeRedisKey(self::MapSectionBlock, $arrKeys);
            //format
            $blockParams = Zend_Json::encode($blockParams);
            //save changes
            $return = $redisInstance->hSet($keyMapSectionBlock, $order, $blockParams);
            return $return;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    
    /**
     * 
     * @param type $params
     * @return type
     * @throws Core_Exception 
     */
    public function getMapBlockSection($params)
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
   
            //make redis key
            $arrKeys = array($params['BlockName'], $params['BlockSection']);
            
            $keyMapSectionBlock = Fpt_Caching_Redis::makeRedisKey(self::MapSectionBlock, $arrKeys);
            
            
            //set detail to cache
            $return = $redisInstance->hGetAll($keyMapSectionBlock);
          
            return $return;

        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    
    /**
     * Search Layout From Cate & Controllder
     * @param array $params array(CateID, Controller)
     * @return mix success?string:false
     * @throws Core_Exception 
     */
    public function getMapLayout($params)
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
            //make redis key
            $arrKeys = array($params['CateID'], $params['Module'], $params['Controller'], $params['Action']);
            $keyLayout = Fpt_Caching_Redis::makeRedisKey(self::MapLayout, $arrKeys);
            //temp
            $mapRS = $redisInstance->get($keyLayout);

            return $mapRS;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    /**
     * Add 1 Block with default view
     * @param array $params
     * @return bool
     * @throws Core_Exception 
     */
    public function addBlock($params)
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
            //make redis key
            $keyBlock = Fpt_Caching_Redis::makeRedisKey(self::BlockDetail, $params['BlockSafeName']);
            //encode params
            $params = Zend_Json::encode($params);
            $return = $redisInstance->set($keyBlock, $params);
            
            return $return;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    /**
     * Get Block
     * @param type $blockNames
     * @param type $cateID
     * @param type $controller
     * @return type
     * @throws Core_Exception 
     */
    public function getBlockByNames($blockNames, $cateID = 0, $controller = '')
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
            $return = false;
            if(is_array($blockNames))
            {
                foreach($blockNames as $blockName)
                {
                    if(!empty($blockName))
                    {
                        //make redis key
                        $keyBlock = Fpt_Caching_Redis::makeRedisKey(self::BlockDetail, $blockName);
                        //get default view & conf
                        $returnView = $redisInstance->get($keyBlock);
                        if($cateID != 0 && !empty($controller))
                        {
                            //check if we have other view specify for this cate & controller
                            $keyMapView = Fpt_Caching_Redis::makeRedisKey(self::MapBlockView, array($cateID, $controller, $blockName));
                            //get custom view
                            $customView = $redisInstance->get($keyMapView);
                            if($customView !== false)
                            {
                                //assign custom view
                                $returnView['BlockView'] = $customView;
                            }  
                        }
                        //format retun
                        $return[$blockName] = $returnView;
                    }
                }
            }
            
            return $return;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    
    public function addSection($params, $blockIDs = array())
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
            //make redis key
            $keySectionDetail = Fpt_Caching_Redis::makeRedisKey(self::SectionDetail, $params['SectionSafeName']);
            //encode params
            $paramCache = Zend_Json::encode($params);
            //temp
            $return[] = $redisInstance->set($keySectionDetail, $paramCache);
            
            if(is_array($blockIDs))
            {
                $keySectionList = Fpt_Caching_Redis::makeRedisKey(self::SectionList, $params['SectionSafeName']);
                $key = $redisInstance->hLen($keySectionList);
                foreach($blockIDs as $score => $blockID)
                {
                    if(!empty($blockID))
                    {
                        $key++;
                        $return[] = $redisInstance->hSet($keySectionList, $key, $blockID);
                    }
                }
            }
            return $return;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    
    
    public function getSection($arrSafeName)
    {
        try
        {
            if(is_array($arrSafeName))
            {
                
                foreach($arrSafeName as $sectionSafeName)
                {
                    //get instance redis
                    $redis = Fpt_Caching_Redis::getInstance('default', 'block');
                    //get db in 1 database
                    $redisInstance = $redis->getRedisStorage(1);
                    //make redis key
                    $keySectionDetail = Fpt_Caching_Redis::makeRedisKey(self::SectionDetail, $sectionSafeName);
                    //get detail
                    $return[$sectionSafeName]['detail'] = $redisInstance->get($keySectionDetail);

                    $keySectionList = Fpt_Caching_Redis::makeRedisKey(self::SectionList, $sectionSafeName);

                    $return[$sectionSafeName]['list'] = $redisInstance->hGetAll($keySectionList);
                    
                }
                return $return;
            }
            
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    
    public function getLayout($params)
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
            //make redis key
            $keyLayout = Fpt_Caching_Redis::makeRedisKey(self::LayoutDetail, $params['LayoutName']);

            //get layout detail
            $return = $redisInstance->get($keyLayout);
            return $return;
           
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    /**
     * Get List Layout
     * @return type
     * @throws Core_Exception 
     */
    public function getListLayout()
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
            //make redis key
            $keyLayout = Fpt_Caching_Redis::makeRedisKey(self::LayoutDetail, '*');
      
            //get all keys layout name
            $return = $redisInstance->keys($keyLayout);
            array_walk($return, 'Fpt_Caching_Redis::removeKeyPrefix', self::LayoutDetail);
            return $return;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    
    public function getListSection()
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
            //make redis key
            $keyLayout = Fpt_Caching_Redis::makeRedisKey(self::SectionDetail, '*');
            
            //get all keys layout name
            $return = $redisInstance->keys($keyLayout);
            //remove prefix
            array_walk($return, 'Fpt_Caching_Redis::removeKeyPrefix', self::SectionDetail);

            return $return;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    
    public function getListBlock()
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
            //make redis key
            $keyLayout = Fpt_Caching_Redis::makeRedisKey(self::BlockDetail, '*');
      
            //get all keys layout name
            $return = $redisInstance->keys($keyLayout);
          
            array_walk($return, 'Fpt_Caching_Redis::removeKeyPrefix', self::BlockDetail);
 
            return $return;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
    
    public function getAutoID($type='layout')
    {
        try
        {
            //get instance redis
            $redis = Fpt_Caching_Redis::getInstance('default', 'block');
            //get db in 1 database
            $redisInstance = $redis->getRedisStorage(1);
            //make redis key
            switch($type)
            {
                case 'layout':
                    $key = Fpt_Caching_Redis::makeRedisKey(self::LayoutID, '');
                    break;
                case 'block':
                    $key = Fpt_Caching_Redis::makeRedisKey(self::BlockID, '');
                    break;
                case 'section':
                    $key = Fpt_Caching_Redis::makeRedisKey(self::SectionID, '');
                    break;
                case 'map':
                    $key = Fpt_Caching_Redis::makeRedisKey(self::SectionID, '');
                    break;
                default:break;
            }
                        
            //Adds the specified member with a given score to the sorted set stored at key.
            $rs = $redisInstance->incr($key);
            if ($rs % 100 == 0)
            {
                $redisInstance->bgSave();
            }
            //Return value: Long 1 if the element is added. 0 otherwise.
            return $rs;
        } 
        catch (Exception $ex)
        {
            throw new Core_Exception($ex->getMessage(), $ex->getCode());
        }
    }
 
    
}